﻿//*** Guidance generated code ***//
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;

using ProjectBase.Core;

using Survey.Common.Business;
using Survey.Common.Data;
using Survey.Entity;

namespace Survey.Business
{
    /// <summary>
    ///     The base Facade for ICodelists
    /// </summary>
    /// <typeparam name = "TCodeList"></typeparam>
    public abstract class CodeListFacade<TCodeList>
        : CodeListFacade<TCodeList, CodeListFilter, ICodeListDao<TCodeList, CodeListFilter>>
        where TCodeList : class, ICodeList, new() {}

    /// <summary>
    ///     The base Facade for ICodelists, which need to extend the Code,Name,IsVisible and ID properties (e.g. with Suffix)
    /// </summary>
    /// <typeparam name = "T"></typeparam>
    /// <typeparam name = "TFilter"></typeparam>
    public abstract class CodeListFacade<T, TFilter>
        : CodeListFacade<T, TFilter, ICodeListDao<T, TFilter>>
        where T : class, ICodeList, new()
        where TFilter : CodeListFilter, new() {}

    /// <summary>
    ///     CodeList base Facade, which allowes to set even the IDao type
    /// </summary>
    /// <typeparam name = "TEntity"></typeparam>
    /// <typeparam name = "TFilter"></typeparam>
    /// <typeparam name = "TDao"></typeparam>
    public abstract class CodeListFacade<TEntity, TFilter, TDao>
        : BaseFacade<TEntity, int, TFilter, TDao>, ICodeListFacade<TEntity, TFilter>
        where TEntity : class, ICodeList, new()
        where TFilter : CodeListFilter, new()
        where TDao : class, ICodeListDao<TEntity, TFilter>
    {
        #region constructor
        /// <summary>
        ///     appends Clear() to Change event
        /// </summary>
        static CodeListFacade()
        {
            ChangeHandler += Clear;
        }
        #endregion constructor

        #region ICodeListFacade<T>
        /// <summary>
        ///     Returns new ICodeList enity of type 'T'
        ///     with rovided code. Name is set to 'code' and IsVisible to true
        /// </summary>
        /// <returns></returns>
        public override TEntity CreateNew()
        {
            var entity = new TEntity
            {
                Code = string.Empty,
                Name = string.Empty,
                IsVisible = true
            };
            return entity;
        }

        /// <summary>
        ///     Returns new ICodeList enity of type 'T'
        ///     with rovided code. Name is set to 'code' and IsVisible to true
        /// </summary>
        /// <param name = "code">not null nor empty code string</param>
        /// <returns></returns>
        public virtual TEntity CreateNew(string code)
        {
            return CreateNew(code, code, true);
        }

        /// <summary>
        ///     Returns new ICodeList enity of type 'T'
        ///     with rovided code and name. IsVisible is set to true
        /// </summary>
        /// <param name = "code">not null nor empty code string</param>
        /// <param name = "name">not mepty name string</param>
        /// <returns></returns>
        public virtual TEntity CreateNew(string code, string name)
        {
            return CreateNew(code, name, true);
        }

        /// <summary>
        ///     Returns new ICodeList enity of type 'T'
        ///     with rovided code, name and isVisible
        /// </summary>
        /// <param name = "code">not null nor empty code string</param>
        /// <param name = "name">not mepty  name string</param>
        /// <param name = "isVisible"></param>
        /// <returns></returns>
        public virtual TEntity CreateNew(string code, string name, bool isVisible)
        {
            var entity = CreateNew(); // this will asure correct call for separate code lists
            entity.Code = code;
            entity.Name = name;
            entity.IsVisible = isVisible;
            return entity;
        }

        /// <summary>
        ///     Returns one 'T' CodeList Value by provided code.
        ///     If nothing is found - null is returned.
        ///     If more then one record exists, exception is thrown
        /// </summary>
        /// <param name = "code"></param>
        /// <returns></returns>
        public virtual TEntity GetByCode(String code)
        {
            return GetAll().Where(item => item.Code.IsEqual(code)).SingleOrDefault();
        }
        #endregion ICodeListFacade<T>

        #region Clear GetAll


        /// <summary>
        ///     Returns the set of all ICodeLists sorted by localized value.
        ///     Result is cached in the static list, enforcing great performance
        /// </summary>
        /// <returns></returns>
        public virtual IEnumerable<TEntity> GetAll()
        {
            var items = Items;
            if (items.IsNull())
            {
                items = Dao.GetAll().Select(c => c.Clone() as TEntity).ToList().AsReadOnly();
                Items = items;
            }

            return items.OrderBy(i => i.ToDisplay());
        }

        /// <summary>
        ///     Returns the set of all ICodeLists sorted by localized value.
        ///     Result is cached in the static list, enforcing great performance.
        ///     Calls the GetAll() and filters the IsVisible == true;
        /// </summary>
        /// <returns></returns>
        public virtual IEnumerable<TEntity> GetAllVisible()
        {
            return GetAll().Where(i => i.IsVisible).ToList();
        }
        /// <summary>
        ///     Clears cached data when any change appear
        /// </summary>
        /// <param name = "sender"></param>
        /// <param name = "args"></param>
        static void Clear(object sender, EventArgs args)
        {
            Items = null;
        }
        #endregion Clear GetAll

        #region properties
        /// <summary>
        ///     Cached collection of All CodeList values
        /// </summary>
        protected static IEnumerable<TEntity> Items { get; set; }
        #endregion properties
    }
}